package com.glc.hms.system.service.impl;

import com.glc.hms.common.util.DateTimeUtils;
import com.glc.hms.system.model.vo.JavaSystemInfoVO;
import com.glc.hms.system.model.vo.MemoryInfo;
import com.glc.hms.system.service.ISystemInfoService;
import com.google.common.collect.Lists;
import com.sun.management.OperatingSystemMXBean;
import org.springframework.stereotype.Service;

import java.lang.management.*;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

/**
 * @author Santa
 * @since 2019/12/5
 */
@Service
public class SystemInfoServiceImpl implements ISystemInfoService {


    /**
     * 查询系统信息
     * @return
     */
    @Override
    public JavaSystemInfoVO querySystemInfo(){
        JavaSystemInfoVO javaSystemInfoVO = new JavaSystemInfoVO();


        //系统运行情况
        OperatingSystemMXBean osmb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
        //编译器和编译情况
        CompilationMXBean cm = ManagementFactory.getCompilationMXBean();
        javaSystemInfoVO.setCompilationName(cm.getName());
        javaSystemInfoVO.setCompilationTime(cm.getTotalCompilationTime()+" 毫秒");

        // Java运行时环境版本
        javaSystemInfoVO.setJavaVersion(System.getProperty("java.version"));
        // Java 运行时环境供应商
        javaSystemInfoVO.setJavaCompany(System.getProperty("java.vendor"));
        // Java 供应商的URL
        javaSystemInfoVO.setCompanycUrl(System.getProperty("java.vendor.url"));
        // Java安装目录
        javaSystemInfoVO.setJdkInstallAddr(System.getProperty("java.home"));
        // Java 操作系统的名称
        javaSystemInfoVO.setSystemName(System.getProperty("os.name"));
        // Java 操作系统的架构
        javaSystemInfoVO.setSystemFramework(System.getProperty("os.arch"));
        // Java 操作系统的版本
        javaSystemInfoVO.setSystemVersion(System.getProperty("os.version"));


        //运行时情况
        RuntimeMXBean rt = ManagementFactory.getRuntimeMXBean();
        // 系统启动时间
        javaSystemInfoVO.setJVMStartTime(DateTimeUtils.convertDateTimeToString(new Date(ManagementFactory.getRuntimeMXBean().getStartTime())));
        // JVM持续时间
        javaSystemInfoVO.setJVMHoldTime(toDuration(rt.getUptime()));

        javaSystemInfoVO.setTotalMemory(bytesToMB(osmb.getTotalPhysicalMemorySize()));
        javaSystemInfoVO.setFreeMemory(bytesToMB(osmb.getFreePhysicalMemorySize()));
        javaSystemInfoVO.setUserdRatio(new BigDecimal((1 - osmb.getFreePhysicalMemorySize() * 1.0 / osmb.getTotalPhysicalMemorySize()) * 100).setScale(2, BigDecimal.ROUND_HALF_UP) + " %");


        //JVM内存信息
        long mb = 1024 * 1024;
        Runtime runtime = Runtime.getRuntime();
        long total = runtime.totalMemory() / mb;
        long max = runtime.maxMemory() / mb;
        long free = runtime.freeMemory() / mb;
        //最大内存
        javaSystemInfoVO.setJVMMaxMemory(max + " MB");
        //已分配内存
        javaSystemInfoVO.setJVMAlreadyDistribution(total + " MB");
        //已分配内存中的剩余空间
        javaSystemInfoVO.setJVMAlreadyDistributionFree(free  + " MB");
        //最大可用内存
        javaSystemInfoVO.setJVMMaxFree((max - total + free) + " MB");



        //内存池对象
        List<MemoryInfo> list = Lists.newArrayList();
        List<MemoryPoolMXBean> pools = ManagementFactory.getMemoryPoolMXBeans();
        for(MemoryPoolMXBean pool : pools) {
            final String kind = pool.getType().name();
            final MemoryUsage usage = pool.getUsage();
            MemoryInfo memoryInfo = new MemoryInfo();
            memoryInfo.setHeapName(getKindName(kind));
            memoryInfo.setMemoryName(getPoolName(pool.getName()));
            memoryInfo.setInit(bytesToMB(usage.getInit()));
            memoryInfo.setUsed(bytesToMB(usage.getUsed()));
            memoryInfo.setCommitted(bytesToMB(usage.getCommitted()));
            memoryInfo.setMax(bytesToMB(usage.getMax()));
            list.add(memoryInfo);

        }
        javaSystemInfoVO.setList(list);

        return javaSystemInfoVO;
    }

    protected static String getKindName(String kind) {
        if("NON_HEAP".equals(kind)) {
            return "NON_HEAP(非堆内存)";
        }else {
            return "HEAP(堆内存)";
        }
    }

    protected static String getPoolName(String poolName) {
        switch (poolName) {
            case "Code Cache":
                return poolName +"(代码缓存区)";
            case "Metaspace":
                return poolName +"(元空间)";
            case "Compressed Class Space":
                return poolName +"(类指针压缩空间)";
            case "PS Eden Space":
                return poolName +"(伊甸园区)";
            case "PS Survivor Space":
                return poolName +"(幸存者区)";
            case "PS Old Gen":
                return poolName +"(老年代)";
            default:
                return poolName;
        }
    }
    private static NumberFormat fmtI = new DecimalFormat("###,###", new DecimalFormatSymbols(Locale.ENGLISH));
    private static NumberFormat fmtD = new DecimalFormat("###,##0.000", new DecimalFormatSymbols(Locale.ENGLISH));



    protected static String bytesToMB(long bytes) {
        return fmtI.format((long)(bytes / 1024 / 1024)) + " MB";
    }


    protected static String toDuration(double uptime) {
        uptime /= 1000;
        if (uptime < 60) {
            return fmtD.format(uptime) + " 秒钟";
        }
        uptime /= 60;
        if (uptime < 60) {
            long minutes = (long) uptime;
            String s = fmtI.format(minutes) +  " 分钟";
            return s;
        }
        uptime /= 60;
        if (uptime < 24) {
            long hours = (long) uptime;
            long minutes = (long) ((uptime - hours) * 60);
            String s = fmtI.format(hours) + "小时";
            if (minutes != 0) {
                s += " " + fmtI.format(minutes) + "分钟";
            }
            return s;
        }
        uptime /= 24;
        long days = (long) uptime;
        long hours = (long) ((uptime - days) * 24);
        String s = fmtI.format(days) + "天";
        if (hours != 0) {
            s += " " + fmtI.format(hours) + "小时";
        }
        return s;
    }

}























